﻿using System;

namespace MiniGert
{
  /// <summary>
  /// LineSegment is a line starting at Point1 and ending at Point2.
  /// </summary>
  public class LineSegment
  {
    private Point _point1 = null;
    private Point _point2 = null;

    /// <summary>
    /// Creates a new line segment with both points at (0, 0).
    /// </summary>
    public LineSegment()
    {
      _point1 = new Point();
      _point2 = new Point();
    }

    /// <summary>
    /// Creates a new line segment using the given points.
    /// </summary>
    /// <param name="point1">The starting point.</param>
    /// <param name="point2">The ending point.</param>
    public LineSegment(Point point1, Point point2)
    {
      _point1 = point1;
      _point2 = point2;
    }

    /// <summary>
    /// Creates a new line starting at (x1, y1) and ending a (x2, y2).
    /// </summary>
    /// <param name="x1">The x component of the starting point.</param>
    /// <param name="y1">The y component of the starting point.</param>
    /// <param name="x2">The x component of the ending point.</param>
    /// <param name="y2">The y component of the ending point.</param>
    public LineSegment(float x1, float y1, float x2, float y2)
    {
      _point1 = new Point(x1, y1);
      _point2 = new Point(x2, y2);
    }

    /// <summary>
    /// Gets or sets the starting point.
    /// </summary>
    public Point Point1
    {
      get { return _point1; }
      set { _point1 = value; }
    }

    /// <summary>
    /// Gets or sets the ending point.
    /// </summary>
    public Point Point2
    {
      get { return _point2; }
      set { _point2 = value; }
    }

    /// <summary>
    /// Gets the magnitude (length) of the line segment by using the pythogarean theorem.
    /// </summary>
    public float Magnitude
    {
      get 
      {
        float x = _point1.X - _point2.X;
        float y = _point1.Y - _point2.Y;
        return (float)Math.Sqrt(x * x + y * y); 
      }
    }

    /// <summary>
    /// Calculates the intersection point of the line segment with another. If the two line segment intersect
    /// the intersection point is returned. If the two line segments do not intersect, null is returned.
    /// </summary>
    /// <param name="other">The line segment to test for intersection.</param>
    /// <returns>The Intersection point or null if there is no intersection.</returns>
    public Point Intersects(LineSegment other)
    {
      float x1 = _point1.X;
      float y1 = _point1.Y;
      float x2 = _point2.X;
      float y2 = _point2.Y;

      float x3 = other.Point1.X;
      float y3 = other.Point1.Y;
      float x4 = other.Point2.X;
      float y4 = other.Point2.Y;

      float denominator = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
      if (denominator == 0.0f)
        return null;

      float ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator;
      float ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denominator;

      if ((ua >= 0.0f && ua <= 1.0f) && (ub >= 0.0f && ub <= 1.0))
        return new Point(x1 + ua * (x2 - x1), y1 + ua * (y2 - y1));
      else
        return null;
    }

    /// <summary>
    /// Calculates the normal of the line segment. The vector returned is already normalized.
    /// </summary>
    /// <returns>The normal of the line segment.</returns>
    public Vector Normal()
    {
      Vector result = new Vector(_point2.Y - _point1.Y, -(_point2.X - _point1.X));
      result.Normalize();
      return result;
    }

    /// <summary>
    /// Calculaters the point in the middle of the line segment.
    /// </summary>
    /// <returns>The point in the middle of the line segment.</returns>
    public Point MiddlePoint()
    {
      return new Point(_point1.X + ((_point2.X - _point1.X) / 2.0f), _point1.Y + ((_point2.Y - _point1.Y) / 2.0f));
    }

  }
}
